#!/usr/bin/python -B

from string import Template, upper, replace
from copy   import deepcopy

from ApiUtil import outputCode
from ApiUtil import typeIsVoid

from ApiCodeGen import *

from RegalContextInfo import cond

from RegalDispatchShared import dispatchSourceTemplate, apiDispatchFuncInitCode, apiDispatchGlobalFuncInitCode

from RegalDispatchTraceExclude import exclude

##############################################################################################

traceCond = deepcopy(cond)
traceCond['glx'] = 'REGAL_SYS_GLX && REGAL_SYS_X11'

# CodeGen for apitrace integration

def apiTraceFuncDefineCode(apis, args):
  categoryPrev = None
  code = ''

  code += 'namespace Trace\n'
  code += '{\n'

  for api in apis:

    code += '\n'
    if api.name in traceCond:
      code += '#if %s\n' % traceCond[api.name]

    for function in api.functions:
      if getattr(function,'regalOnly',False)==True:
        continue
      if function.name in exclude or function.category in exclude:
        continue

      name   = function.name
      params = paramsDefaultCode(function.parameters, True)
      callParams = paramsNameCode(function.parameters)
      rType  = typeCode(function.ret.type)
      category  = getattr(function, 'category', None)
      version   = getattr(function, 'version', None)

      if category:
        category = category.replace('_DEPRECATED', '')
      elif version:
        category = version.replace('.', '_')
        category = 'GL_VERSION_' + category

      # Close prev category block.
      if categoryPrev and not (category == categoryPrev):
        code += '\n'

      # Begin new category block.
      if category and not (category == categoryPrev):
        code += '// %s\n\n' % category

      categoryPrev = category

      code += '  %s %s(%s);\n' % (rType, name, params)

    if api.name in traceCond:
      code += '#endif // %s\n' % traceCond[api.name]
    code += '\n'

  # Close pending if block.
  if categoryPrev:
    code += '\n'

  code += '} // namespace Trace \n\n'

  for api in apis:

    code += '\n'
    if api.name in traceCond:
      code += '#if %s\n' % traceCond[api.name]

    for function in api.functions:
      if getattr(function,'regalOnly',False)==True:
        continue
      if function.name in exclude or function.category in exclude:
        continue

      name   = function.name
      params = paramsDefaultCode(function.parameters, True)
      callParams = paramsNameCode(function.parameters)
      rType  = typeCode(function.ret.type)
      category  = getattr(function, 'category', None)
      version   = getattr(function, 'version', None)

      if category:
        category = category.replace('_DEPRECATED', '')
      elif version:
        category = version.replace('.', '_')
        category = 'GL_VERSION_' + category

      # Close prev category block.
      if categoryPrev and not (category == categoryPrev):
        code += '\n'

      # Begin new category block.
      if category and not (category == categoryPrev):
        code += '// %s\n\n' % category

      categoryPrev = category

      code += 'static %sREGAL_CALL %s%s(%s) \n{\n' % (rType, 'trace_', name, params)
      code += '  Internal("trace_%s","()");\n' % name
      code += '  Thread::ThreadLocal &_instance = Thread::ThreadLocal::instance();\n'
      if function.needsContext:
        code += '  RegalAssert(_instance.currentContext);\n'
        code += '  Push<DispatchTableGL *> _push(_instance.nextDispatchTable);\n'
        code += '  _instance.nextDispatchTable = _instance.currentContext->dispatcher.trace.next();\n'
      else:
        code += '  Push<DispatchTableGlobal *> _push(_instance.nextDispatchTableGlobal);\n'
        code += '  _instance.nextDispatchTableGlobal = dispatcherGlobal.trace.next();\n'
      code += '  '
      if not typeIsVoid(rType):
        code += '%s ret = ' % rType
      #code += '_next->call(&_next->%s)(%s);\n' % ( name, callParams )
      code += 'Trace::%s(%s);\n' % ( name, callParams )
      if not typeIsVoid(rType):
        code += '  return ret;\n'
      code += '}\n\n'

    if api.name in traceCond:
      code += '#endif // %s\n' % traceCond[api.name]
    code += '\n'

  # Close pending if block.
  if categoryPrev:
    code += '\n'

  return code

def generateTraceSource(apis, args):

  funcDefine     = apiTraceFuncDefineCode( apis, args )
  funcInit       = apiDispatchFuncInitCode( apis, args, 'trace', exclude, lambda x : True, traceCond )
  globalFuncInit = apiDispatchGlobalFuncInitCode( apis, args, 'trace', exclude, lambda x : True, traceCond )

  substitute = {}
  substitute['LICENSE']         = args.license
  substitute['AUTOGENERATED']   = args.generated
  substitute['COPYRIGHT']       = args.copyright
  substitute['DISPATCH_NAME'] = 'Trace'
  substitute['LOCAL_INCLUDE'] = '#include "RegalDispatcherGlobal.h"\n'
  substitute['LOCAL_CODE']    = ''
  substitute['API_DISPATCH_FUNC_DEFINE'] = funcDefine
  substitute['API_DISPATCH_FUNC_INIT'] = funcInit
  substitute['API_DISPATCH_GLOBAL_FUNC_INIT'] = globalFuncInit
  substitute['IFDEF'] = '#if REGAL_TRACE\n\n#ifdef REGAL_NAMESPACE\n#undef REGAL_NAMESPACE\n#endif\n\n'
  substitute['ENDIF'] = '#endif\n'
  outputCode( '%s/RegalDispatchTrace.cpp' % args.srcdir, dispatchSourceTemplate.substitute(substitute))
